package cc.dullsky.lucene.manager;

import java.nio.file.Paths;
import java.text.DateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.concurrent.TimeUnit;

import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.IndexWriterConfig.OpenMode;
import org.apache.lucene.index.TrackingIndexWriter;
import org.apache.lucene.search.ControlledRealTimeReopenThread;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.SearcherFactory;
import org.apache.lucene.search.SearcherManager;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.NIOFSDirectory;

import cc.dullsky.lucene.model.ConfigBean;
import cc.dullsky.lucene.model.IndexConfig;

/**
 * 
 * @author Dull
 *
 */
public class IndexManager {
	private IndexWriter indexWriter;
	private TrackingIndexWriter trackingIndexWriter;
	private SearcherManager searcherManager;
	@SuppressWarnings("rawtypes")
	private ControlledRealTimeReopenThread reopenThread;
	private IndexCommitThread indexCommitThread;
	private ConfigBean configBean;

	private static class LazyIndexManager {
		// 保存系统中的IndexManager对象
		private static HashMap<String, IndexManager> indexManagerMap = new HashMap<String, IndexManager>();

		static {
			for (ConfigBean bean : IndexConfig.getConfig()) {
				indexManagerMap.put(bean.getIndexName(), new IndexManager(bean));
			}
		}
	}

	/**
	 * 获取索引的IndexManager对象
	 * 
	 * @param indexName
	 * @return IndexManager
	 */
	public static IndexManager getIndexManager(String indexName) {
		return LazyIndexManager.indexManagerMap.get(indexName);
	}

	/**
	 * 构造器
	 * 
	 * @param configBean
	 */
	private IndexManager(ConfigBean configBean) {
		this.configBean = configBean;
		String indexFile = configBean.getIndexPath() + "/" + configBean.getIndexName();
		IndexWriterConfig indexWriterConfig = new IndexWriterConfig(configBean.getAnalyzer());
		indexWriterConfig.setOpenMode(OpenMode.CREATE_OR_APPEND);
		Directory directory = null;
		try {
			directory = NIOFSDirectory.open(Paths.get(indexFile));
			this.indexWriter = new IndexWriter(directory, indexWriterConfig);
			this.trackingIndexWriter = new TrackingIndexWriter(indexWriter);
			this.searcherManager = new SearcherManager(trackingIndexWriter.getIndexWriter(), new SearcherFactory());
		} catch (Exception e) {
			e.printStackTrace();
		}
		setThread();
	}

	/**
	 * 获取最新可用的indexSearcher
	 * 
	 * @return IndexSearcher
	 */
	public IndexSearcher getIndexSearcher() {
		try {
			return this.searcherManager.acquire();
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * 释放indexSearcher
	 * 
	 * @param indexSearcher
	 */
	public void relase(IndexSearcher indexSearcher) {
		try {
			this.searcherManager.release(indexSearcher);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 设置indexSearcher的守护线程
	 */
	private void setThread() {
		this.reopenThread = new ControlledRealTimeReopenThread<>(trackingIndexWriter, searcherManager, configBean.getIndexReopenMaxStaleSec(),
				configBean.getIndexReopenMinStaleSec());
		this.reopenThread.setName("SearcherManager reopen thread");
		this.reopenThread.setDaemon(true);
		this.reopenThread.start();

		this.indexCommitThread = new IndexCommitThread(configBean.getIndexName() + " index commit thread");
		this.indexCommitThread.setDaemon(true);
		this.indexCommitThread.start();
	}

	/**
	 * 提交线程
	 */
	private class IndexCommitThread extends Thread {
		private boolean flag = false;

		public IndexCommitThread(String name) {
			super(name);
		}

		@Override
		public void run() {
			flag = true;
			while (flag) {
				try {
					indexWriter.commit();
					System.out.println(DateFormat.getDateTimeInstance().format(new Date()) + "\t" + configBean.getIndexName() + "\tcommit");
					TimeUnit.SECONDS.sleep(configBean.getIndexCommitSeconds());
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
			super.run();
		}
	}

	public void commit() {
		try {
			indexWriter.commit();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public IndexWriter getIndexWriter() {
		return indexWriter;
	}

	public TrackingIndexWriter getTrackingIndexWriter() {
		return trackingIndexWriter;
	}

}
